package com.zivwu.library.ui.image;


import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;

import com.zivwu.library.dao.local.cache.DiskLruCache;
import com.zivwu.library.utils.MD5;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;

import javax.inject.Inject;
import javax.inject.Named;

import okio.BufferedSink;
import okio.Okio;

public class ImageCompress {
    private int DEFAULT_MAX_FILE_SIZE = 200 * 1024;
    private int DEF_OUT_WIDTH = 720;
    private int DEF_OUT_HEIGHT = 1280;
    private DiskLruCache cache;

    @Inject
    public ImageCompress(@Named("image") DiskLruCache cache) {
        this.cache = cache;
    }

    public String compress(String path) throws IOException, OutOfMemoryError {
        return compress(path, DEF_OUT_WIDTH, DEF_OUT_HEIGHT);
    }

    public String compress(String path, int outWidth, int outHeight) throws IOException {
        //检查是否已经进行缓存
        String key = new MD5().hashKeyForDisk(path);
        File file = getDirtyFile(cache.getDirectory(), key, 0);
        String cachePath = file.getAbsolutePath();
        DiskLruCache.Snapshot snapshot = cache.get(key);
        if (snapshot != null) {
            return cachePath;
        }

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;

        BitmapFactory.decodeFile(path, options);
        float height = options.outHeight;
        float width = options.outWidth;
        float min = Math.min(height / outHeight, width / outWidth);
        options.inSampleSize = 1;
        while (min / 2 > 2) {
            min /= 2;
            options.inSampleSize *= 2;
        }
        int actualOutWidth = (int) width;
        int actualOutHeight = (int) height;

        if (min > 1) {
            actualOutWidth /= min;
            actualOutHeight /= min;
        }
        options.inJustDecodeBounds = false;
        Bitmap sampleBitmap = BitmapFactory.decodeFile(path, options);

        if (sampleBitmap == null)
            return null;

        Bitmap scaledBitmap = Bitmap.createScaledBitmap(sampleBitmap, actualOutWidth, actualOutHeight, true);
        if (!sampleBitmap.equals(scaledBitmap))
            sampleBitmap.recycle();


        ExifInterface exif = new ExifInterface(path);
        int orientation = exif.getAttributeInt(
                ExifInterface.TAG_ORIENTATION, 0);
        Matrix matrix = new Matrix();
        if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
            matrix.postRotate(90);
        } else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
            matrix.postRotate(180);
        } else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
            matrix.postRotate(270);
        }
        scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0,
                scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);


        //进行有损压缩
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int options_ = 100;
        scaledBitmap.compress(Bitmap.CompressFormat.JPEG, options_, baos);//质量压缩方法，把压缩后的数据存放到baos中 (100表示不压缩，0表示压缩到最小)


        while (baos.size() > DEFAULT_MAX_FILE_SIZE) {
            baos.reset();
            options_ = Math.max(0, options_ - 10);
            scaledBitmap.compress(Bitmap.CompressFormat.JPEG, options_, baos);
            if (options_ == 50)
                break;
        }
        DiskLruCache.Editor edit = cache.edit(key);
        BufferedSink buffer = Okio.buffer(Okio.sink(edit.newOutputStream(0)));
        buffer.write(baos.toByteArray());
        buffer.flush();
        edit.commit();
        buffer.close();
        cache.flush();

        return cachePath;

    }


    private String getName(String content) {
        return content.substring(content.lastIndexOf("/"), content.length() - 1);
    }

    private File getDirtyFile(File directory, String key, int i) {
        return new File(directory, key + "." + i);
    }


    public DiskLruCache getCache(){
        return cache;
    }

}
